package cn.lau.demo.config;

import cn.lau.demo.auth.AuthRealm;
import cn.lau.demo.auth.JWTFilter;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

	private final static String ALG_NAME = "MD5";

	@Bean("securityManager")
	public SecurityManager securityManager(@Qualifier("realm") Realm realm) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 指定执行认证授权逻辑的realm
		securityManager.setRealm(realm);

		/*
		 * 取消使用Shiro默认的基于Session的会话管理
		 * 关闭shiro自带的session，详情见文档
		 * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
		 */
		DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
		DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
		defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
		subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
		securityManager.setSubjectDAO(subjectDAO);

		return securityManager;
	}

	@Bean
	public HashedCredentialsMatcher credentialsMatcher() {
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
		credentialsMatcher.setHashAlgorithmName(ALG_NAME);
		return credentialsMatcher;
	}

	@Bean("realm")
	public Realm realm() {
		AuthRealm authRealm = new AuthRealm();
		authRealm.setCredentialsMatcher(credentialsMatcher());
		return authRealm;
	}

	@Bean("shiroFilter")
	public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
		shiroFilter.setSecurityManager(securityManager);

		// 添加自定义过滤器并取名为jwt
		Map<String, Filter> filterMap = new HashMap<>();
		filterMap.put("jwt", new JWTFilter());
		shiroFilter.setFilters(filterMap);

		// 无权限页面. 会到Request Handler中查找Mapping了该url的handler进行处理
		shiroFilter.setUnauthorizedUrl("/u/unauthorized");
		// 登录页
		shiroFilter.setLoginUrl("/u/notLogin");

		Map<String, String> filterChain = new LinkedHashMap<>();
		filterChain.put("/u/login", "anon");
		filterChain.put("/u/logout", "anon");
		// 除例如登录登出等这类不需要已授权才能访问的路径之外的所有路径都需要通过自定义的JWTFilter
		filterChain.put("/**", "jwt");
		// 其他路径
		// filterChain.put("/**", " authc");

		shiroFilter.setFilterChainDefinitionMap(filterChain);

		return shiroFilter;
	}

	/**
	 * 开启Shiro Aop注解支持
	 * 使用代理方式所有需要开启代码支持
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}

}
